﻿using System;
using System.Data;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.Collections.Generic;
using System.Data.Objects.DataClasses;

namespace SilverlightSdms.Web.Services
{
    [ServiceContract(Namespace = "")]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class UsersService
    {
        private readonly SdmsEntities _context = new SdmsEntities();

        [OperationContract]
        public List<LightUser> GetUsersWithRoles()
        {
            List<LightUser> users = new List<LightUser>();
            
            {
                var list = from user in _context.Users
                           from userRole in _context.UserRoles
                           from role in _context.Roles
                           where user.Id == userRole.User.Id
                           && role.Id == userRole.Role.Id
                           select new { user.Id, user.Name, user.Password, role.RoleType };
                
                foreach (var item in list)
                {
                    LightUser foundUser = users.Find(u => u.Id == item.Id);

                    if (foundUser == null)
                    {
                        users.Add(new LightUser(item.Id, item.Name, item.Password, item.RoleType));
                    }
                    else
                    {
                        if (foundUser.Roles.Find(r => r.ToLower() == item.RoleType.ToLower()) == null)
                        {
                            foundUser.Roles.Add(item.RoleType);
                        }
                    }
                }
            }
            return users;
        }

        [OperationContract]
        public List<User> GetAllUsers()
        {
            var queryable = from user in _context.Users select user;
            return queryable.ToList();
        }

        [OperationContract]
        public List<User> GetUsers()
        {
                return (from user in _context.Users select user).ToList();
        }

        [OperationContract]
        public User GetUser(int userID)
        {
            List<User> allUsers = GetAllUsers();

            return allUsers.Find(u => u.Id == userID);
        }

        [OperationContract]
        public int SaveSchool(School school,int regionId)
        {

            if (school.Id == 0)
            {
                setSchoolRegion(school, regionId);
                _context.Schools.AddObject(school);
            }
            else
            {
                _context.Schools.Attach(school);
                _context.ObjectStateManager.ChangeObjectState(school, System.Data.EntityState.Modified);
                setSchoolRegion(school, regionId);
                _context.Schools.ApplyCurrentValues(school);
            }

            _context.SaveChanges();
            return school.Id;
        }

        private void setSchoolRegion(School school, int regionId)
        {
            var regionToSet = (from region in _context.Regions where region.Id == regionId select region).First();
            school.Region = regionToSet;
        }

        [OperationContract]
        public IEnumerable<School> FindAllSchools()
        {
            return (from school in _context.Schools select school).ToList();
        }

        [OperationContract]
        public void DeleteSchool(School school)
        {
            _context.Schools.Attach(school);
            _context.ObjectStateManager.ChangeObjectState(school, System.Data.EntityState.Deleted);
            _context.Schools.DeleteObject(school);

            _context.SaveChanges();
        }

        [OperationContract]
        public int AddUser(User user, IEnumerable<Role> roles)
        {

            
                if (user.Id == 0)
                {
                    _context.Users.AddObject(user);
                    foreach (var userRole in user.UserRole)
                    {
                        if (userRole.Id == 0)
                        {
                            _context.UserRoles.AddObject(userRole);
                        }
                    }
                }
                else
                {
                    _context.Users.Attach(user);
                    _context.Users.ApplyCurrentValues(user);
                    _context.ObjectStateManager.ChangeObjectState(user, System.Data.EntityState.Modified);

                    // update roles
                    //_context.Users.Attach(user);

                }

                updateRoles(user, _context, roles);

                _context.SaveChanges();
            return user.Id;
        }

        private void updateRoles(User user, SdmsEntities context, IEnumerable<Role> roles)
        {
            List<UserRole> userRoles = (from userRole in context.UserRoles
                                        where
                                            userRole.User.Id == user.Id
                                        select userRole).ToList();


            foreach (var userRole in userRoles)
            {
                if (!roles.Any(r => r.Id == userRole.Role.Id))
                {
                    context.UserRoles.Attach(userRole);
                    context.ObjectStateManager.ChangeObjectState(userRole, System.Data.EntityState.Deleted);
                    context.UserRoles.DeleteObject(userRole);
                }
            }

            foreach (Role role in roles)
            {
                if (!user.UserRole.Any(ur => ur.Role.Id == role.Id))
                {
                    UserRole userRole = context.UserRoles.CreateObject();
                    userRole.User = user;
                    userRole.Role = (from r in context.Roles where r.Id == role.Id select r).First() ;
                    user.UserRole.Add(userRole);
                    context.UserRoles.AddObject(userRole);
                }
            }
        }

        [OperationContract]
        public List<Role> FindAllRoles()
        {
            List<Role> roles = (from role in _context.Roles select role).ToList();
            return roles;
        }

        /// <summary>
        /// Gets all the users wich belong to same team as the given user
        /// </summary>
        /// <param name="userId">ID of the given user</param>
        /// <returns>List of users</returns>
        [OperationContract]
        public List<User> GetTeamUsers(int userId)
        {
            List<User> users = new List<User>();
            
            var teams = _context.Teams.Where(t => t.TeamLeaderId == userId);

            if (teams != null && teams.Count() > 0)
            {
                Team team = teams.First();
                foreach (var item in team.TeamMember)
                {
                    users.Add(item.User);
                }
            }

            return users;
        }

        [OperationContract]
        public void DeleteUser(int userId)
        {
            var userRoles = (from ur in _context.UserRoles where ur.User.Id == userId select ur).ToList();

            foreach (var userRole in userRoles)
            {
                _context.UserRoles.Attach(userRole);
                _context.ObjectStateManager.ChangeObjectState(userRole, System.Data.EntityState.Deleted);
                _context.UserRoles.DeleteObject(userRole);
            }

            var user = (from u in _context.Users
                         where u.Id == userId
                         select u).First();

            _context.Users.Attach(user);
            _context.ObjectStateManager.ChangeObjectState(user, System.Data.EntityState.Deleted);
            _context.Users.DeleteObject(user);

            _context.SaveChanges();
        }

        [OperationContract]
        public int CreateRegion(Region region)
        {
            _context.Regions.AddObject(region);

            _context.SaveChanges();

            return region.Id;
        }

        [OperationContract]
        public void DeleteRegion(Region region)
        {
            _context.Regions.Attach(region);
            _context.ObjectStateManager.ChangeObjectState(region, System.Data.EntityState.Deleted);
            _context.Regions.DeleteObject(region);

            _context.SaveChanges();
        }

        [OperationContract]
        public IEnumerable<Region> FindAllRegions()
        {
            return (from region in _context.Regions select region).ToList();
        }

        [OperationContract]
        public List<Team> FindAllTeams()
        {
            List<Team> teams = (from team in _context.Teams select team).ToList();
            return teams;
        }

        [OperationContract]
        public void AddTeam(Team team, int? RegionId, List<int> UserIds)
        {
            if (team.Id == 0)
            {
                if (RegionId != null && RegionId.HasValue)
                {
                    var region = _context.Regions.First(r => r.Id == RegionId);
                    team.Regions.Add(region);
                }
                _context.Teams.AddObject(team);
            }

            _context.SaveChanges();

            ChangeTeamMembers(team.Id, UserIds);
        }

        [OperationContract]
        public void UpdateTeam(int TeamId, string TeamName, int? RegionId, int LeaderId, List<int> UserIds)
        {
            var team = _context.Teams.First(t => t.Id == TeamId);
            team.Name = TeamName;
            team.TeamLeaderId = LeaderId;
            if (RegionId != null && RegionId.HasValue)
            {
                var newRegion = _context.Regions.First(r => r.Id == RegionId);
                team.Regions.Add(newRegion);
            }
            _context.Teams.ApplyCurrentValues(team);
            _context.ObjectStateManager.ChangeObjectState(team, System.Data.EntityState.Modified);
            _context.SaveChanges();

            ChangeTeamMembers(TeamId, UserIds);
        }

        [OperationContract]
        public void DeleteTeam(int TeamId)
        {
            var team = _context.Teams.First(t => t.Id == TeamId);

            var teamMemberList = new List<TeamMember>(team.TeamMember);

            foreach (var item in teamMemberList)
            {
                _context.ObjectStateManager.ChangeObjectState(item, System.Data.EntityState.Deleted);
            }
            team.TeamMember.Clear();
            List<Region> regions = team.Regions.ToList();
            foreach (var region in regions)
            {
                region.Team = null;
                _context.ObjectStateManager.ChangeObjectState(region, System.Data.EntityState.Modified);
            }
            _context.ObjectStateManager.ChangeObjectState(team, System.Data.EntityState.Deleted);
            _context.SaveChanges();
        }

        public void ChangeTeamMembers(int TeamId, List<int> UserIds)
        {
            var team = _context.Teams.First(t => t.Id == TeamId);

            var teamMemberList = new List<TeamMember>(team.TeamMember);

            foreach (var item in teamMemberList)
            {
                _context.ObjectStateManager.ChangeObjectState(item, System.Data.EntityState.Deleted);
            }
            team.TeamMember.Clear();

            foreach (var userId in UserIds)
            {
                var teamMember = new TeamMember();
                teamMember.User = _context.Users.First(u => u.Id == userId);
                team.TeamMember.Add(teamMember);
            }

            

            _context.Teams.ApplyCurrentValues(team);
            _context.ObjectStateManager.ChangeObjectState(team, System.Data.EntityState.Modified);
            _context.SaveChanges();
        }



        // Add more operations here and mark them with [OperationContract]
    }

    public class LightUser
    {
        public int Id { get; set; }
        public string UserName { get; set; }
        public string Password { get; set; }
        public List<string> Roles { get; set; }

        public LightUser()
        {
            Roles = new List<string>();
        }

        public LightUser(int id, string user, string pass)
        {
            Id = id;
            UserName = user;
            Password = pass;
        }

        public LightUser(int id, string user, string pass, string role)
        {
            Id = id;
            UserName = user;
            Password = pass;
            Roles = new List<string>();
            Roles.Add(role);
        }
    }
}
